package org.wangzx.framework.security.config;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.wangzx.framework.security.api.DefaultWzxUserDetailService;
import org.wangzx.framework.security.api.WzxUserDetailService;
import org.wangzx.framework.security.constant.SecurityConstant;
import org.wangzx.framework.security.encoder.Md5PasswordEncoder;
import org.wangzx.framework.security.jwt.JWTAuthenticationFilter;
import org.wangzx.framework.security.jwt.JWTLoginFilter;
import org.wangzx.framework.security.properties.SecurityProperties;

import static org.wangzx.framework.security.constant.SecurityConstant.DEFAULT_LOGIN_PROCESSING_URL_FORM;
import static org.wangzx.framework.security.constant.SecurityConstant.DEFAULT_UNAUTHENTICATION_URL;

/**
 * Created by WangZX on 2018/7/12.
 */
@Configuration
public class SecurityConfig extends UserSecurityConfig {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private AuthenticationSuccessHandler defaultAuthenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler defaultAuthenticationFailureHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        applyAuthenticationConfig(http);
        if (StringUtils.equals(securityProperties.getLoginType(),SecurityConstant.LOGIN_TYPE_JWT)){
            applyJwtConfig(http);
        }else {
            applySessionConfig(http);
        }
    }

    private void applyJwtConfig(HttpSecurity http)throws Exception{
        JWTLoginFilter jwtLoginFilter = new JWTLoginFilter(authenticationManager());
        JWTAuthenticationFilter jwtAuthenticationFilter = new JWTAuthenticationFilter(authenticationManager());
        jwtLoginFilter.setSecurityProperties(securityProperties);
        jwtLoginFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(DEFAULT_LOGIN_PROCESSING_URL_FORM, "POST"));
        jwtLoginFilter.setAuthenticationSuccessHandler(defaultAuthenticationSuccessHandler);
        jwtLoginFilter.setAuthenticationFailureHandler(defaultAuthenticationFailureHandler);

        http
                .addFilter(jwtLoginFilter)
                .addFilter(jwtAuthenticationFilter)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    private void applySessionConfig(HttpSecurity http)throws Exception{
        http.formLogin()
                .loginPage(DEFAULT_UNAUTHENTICATION_URL)
                .loginProcessingUrl(DEFAULT_LOGIN_PROCESSING_URL_FORM)
                .successHandler(defaultAuthenticationSuccessHandler)
                .failureHandler(defaultAuthenticationFailureHandler);
    }


    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder passwordEncoder() {
        if (StringUtils.equals(securityProperties.getEncoderType(), SecurityConstant.PASSWORD_ENCODER_BCrypt)){
            return new BCryptPasswordEncoder();
        }else if (StringUtils.equals(securityProperties.getEncoderType(),SecurityConstant.PASSWORD_ENCODER_MD5)){
            return new Md5PasswordEncoder();
        }
        throw new RuntimeException("密码加密方式未设置");
    }

    @Bean
    @ConditionalOnMissingBean(WzxUserDetailService.class)
    public WzxUserDetailService wzxUserDetailService(){
        DefaultWzxUserDetailService defaultWzxUserDetailService = new DefaultWzxUserDetailService();
        defaultWzxUserDetailService.setPasswordEncoder(passwordEncoder());
        return defaultWzxUserDetailService;
    }
}
